#pragma once

#include <math.h>
#include <iostream>
#include "math_util.h"

using namespace std;

class Vector3d {
public:
    union {
        struct {
            double x, y, z;
        };
        double e[3];
    };

    /* Constructors.
     */

    //Nothing.
    Vector3d();

    Vector3d(double x, double y, double z);

    static Vector3d randomCube(double min, double max);
    
    /* Math, non-operator.
     */

    double magnitude() const;
    double magnitude2d() const;

    //Normalizes this vector. Returns the magnitude of this vector.
    double normalize();

    //Normalizes the x and y components.
    double normalize2d();

    //Gets the slope of this vector.
    double getSlope();

    //Rotates the vector counterclockwise about the z axis.
    void rotateLeft(double angle);

    //Rotates the vector about vector ^ z.
    void rotateUp(double angle);

    //Gets a normalized copy of this vector.
    Vector3d getNormalized() const;

    /* Unary operators.
     */
    Vector3d operator-() const;
    double operator[](int i) const;
    
    /* Binary operators with self.
     */
    Vector3d operator+(const Vector3d& v) const;
    void operator+=(const Vector3d& v);
    Vector3d operator-(const Vector3d& v) const;
    void operator-=(const Vector3d& v);
    
    //Dot product.
    double operator*(const Vector3d& v) const;

    //Cross product.
    Vector3d operator^(const Vector3d& v) const;
    void operator^=(const Vector3d& v);

    /* Binary operators with doubles.
     */
    friend Vector3d operator*(const Vector3d& v, double f);
    friend Vector3d operator*(double f, const Vector3d& v);
    friend Vector3d operator/(const Vector3d& v, double f);
    friend Vector3d operator/(double f, const Vector3d& v);

    void operator*=(double f);
    void operator/=(double f);

    /* Streams.
     */
    friend ostream& operator<<(ostream& os, Vector3d& v);
    friend istream& operator>>(istream& is, Vector3d& v);

    /* Other. */
    bool timeInRect(double& minT, double& maxT, double dirX, double dirY, double minX, double maxX, double minY, double maxY) const;
};
